Skip to content

ADFA-3070 | Fix agent chat unscrollable in landscape - #64

Merged
jatezzz merged 1 commit into
mainfrom
feat/ADFA-3070-landscape-chat-scroll
Aug 13, 2026
Merged

ADFA-3070 | Fix agent chat unscrollable in landscape#64
jatezzz merged 1 commit into
mainfrom
feat/ADFA-3070-landscape-chat-scroll

Conversation

@jatezzz

@jatezzz jatezzz commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Description

Fixed an issue where the agent chat is not scrollable on shorter screens, such as in landscape orientation. The previous LinearLayout setup caused the RecyclerView to be measured at zero height once the UI chrome exceeded the container's height. The layout has been updated to bound the chrome elements and float the composer toggle over the list. Additionally, an auto-hide controller was introduced to fold the composer away on compact screens, ensuring maximum space for the chat history.

Details

  • Extracted the composer behavior into a dedicated ComposerAutoHideController to manage visibility state and auto-hide countdowns.
  • Added integer resources to define compact screens (under 480dp) and trigger auto-hiding after 5 seconds of idle time.
  • Implemented window inset handling to properly pad the RecyclerView around display cutouts in landscape orientation.
  • Consolidated the attachment, input, and send controls into a single bordered composer box layout.
Screen_Recording_20260807_093529_Code.on.the.Go.mp4

Ticket

ADFA-3070

Observation

The auto-hide functionality includes explicit safeguards to ensure the composer remains visible if the user is typing, the input is not empty, the agent is actively running, or if touch exploration accessibility services are enabled.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

Tip: disable this comment in your organization's Code Review settings.

@hal-eisen-adfa

Copy link
Copy Markdown
Contributor

Code review

Found 1 issue:

  1. The composer can reach an unrecoverable hidden state after process death. attach() passes the saved visible flag straight through, and applyCompactRule re-derives only autoHide — not visible. Sequence: fold the composer on a compact screen, the process is killed while backgrounded, the app restores into a taller configuration. autoHide is correctly recomputed to false, but the stale saved visible = false is still applied, so setVisible hides the input bar and hides the tab that would restore it (binding.btnShowComposer.isVisible = autoHide && !visiblefalse && true). The user is left with no input bar, no attach button, and no on-screen affordance to recover the composer.

autoHide = savedState?.getBoolean(KEY_COMPOSER_AUTO_HIDE) ?: false
applyCompactRule(config, visible = savedState?.getBoolean(KEY_COMPOSER_VISIBLE) ?: true)
}

private fun setVisible(visible: Boolean) {
val binding = _binding ?: return
binding.inputBarCard.isVisible = visible
binding.btnShowComposer.isVisible = autoHide && !visible
binding.btnHideComposer.isVisible = autoHide && visible
if (visible) {

onConfigurationChanged already guards the live-rotation case with applyCompactRule(config, visible = true), but attach() never got the equivalent guard:

*/
fun onConfigurationChanged(config: Configuration) =
applyCompactRule(config, visible = true)
/**

The KDoc on saveState already names this exact scenario — "the process can come back in an orientation other than the one it died in, and the saved flag would describe a screen that is gone" — but only autoHide is re-derived on restore, not visible:

/**
* Saves the composer across process death. The auto-hide flag is written too, but
* [applyCompactRule] re-derives it on restore: the process can come back in an orientation
* other than the one it died in, and the saved flag would describe a screen that is gone.
*/
fun saveState(outState: Bundle) {
outState.putBoolean(KEY_COMPOSER_AUTO_HIDE, autoHide)
outState.putBoolean(KEY_COMPOSER_VISIBLE, _binding?.inputBarCard?.isVisible ?: true)
}

Suggested fix: in applyCompactRule, ignore the restored visible = false once autoHide resolves to false, so the composer can only stay folded on a screen that still offers the reopen tab.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@jatezzz
jatezzz force-pushed the feat/ADFA-1798-model-memory-preflight branch from 17a4173 to 3d873f6 Compare August 11, 2026 13:09
@jatezzz
jatezzz force-pushed the feat/ADFA-3070-landscape-chat-scroll branch 3 times, most recently from d959d7b to 3793da9 Compare August 11, 2026 21:16
@hal-eisen-adfa

Copy link
Copy Markdown
Contributor

Code review

Found 1 issue:

  1. The manual fold path has no agentRunning guard, so the Hide tab can fold the Stop button away mid-run (bug due to ComposerAutoHideController.kt: canAutoHide()'s return !agentRunning is consulted only by schedule(), so it blocks the idle-timeout fold but not a tap on btnHideComposer)

The KDoc on onAgentRunningChanged states that "a running agent also pins the composer open for as long as the run lasts":

/**
* Switches the trailing button between Send and Stop. Stop lives on that button, so a running
* agent also pins the composer open for as long as the run lasts.
*/
fun onAgentRunningChanged(running: Boolean) {

But setVisible never checks agentRunning:

*/
private fun setVisible(visible: Boolean) {
val binding = _binding ?: return
binding.inputBarCard.isVisible = visible
binding.btnShowComposer.isVisible = autoHide && !visible
binding.btnHideComposer.isVisible = autoHide && visible
if (visible) {
schedule()
} else {
countdown?.cancel()
binding.promptInputEdittext.clearFocus()
hideKeyboard()
}
}

On a compact screen this is reachable on exactly the screen class the PR targets: onAgentRunningChanged(true) calls setVisible(true), which makes btnHideComposer visible (autoHide && visible), and its click listener routes straight to setVisible(false), hiding inputBarCard and the Stop button it carries.

Recovery is a single tap on the still-visible btnShowComposer, so this is low severity. Either honour agentRunning on the manual path, or soften the KDoc so it does not promise a guarantee the code does not make.

Reviewed against base feat/ADFA-1798-model-memory-preflight (stacked PR), so PR #63's commits were excluded. Code review only, not device-verified.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@jatezzz

jatezzz commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

@hal-eisen-adfa Good catch on the mismatch. Keeping the manual path as-is and fixing the doc instead: folding the composer to read streaming output on a short landscape screen is a reasonable thing to want mid-run, and gating the tap would leave a visible button that does nothing. Reworded the KDoc so it only promises what the code does, the run opens the composer and suppresses the idle countdown; an explicit Hide still folds it, with Stop one tap away on the reopen tab.

@jatezzz
jatezzz force-pushed the feat/ADFA-1798-model-memory-preflight branch from 3505241 to 3c1b4de Compare August 12, 2026 14:50
@jatezzz
jatezzz force-pushed the feat/ADFA-3070-landscape-chat-scroll branch from 638fcf8 to 4e1d431 Compare August 12, 2026 14:57
Base automatically changed from feat/ADFA-1798-model-memory-preflight to main August 12, 2026 16:52
@jatezzz
jatezzz force-pushed the feat/ADFA-3070-landscape-chat-scroll branch from 4e1d431 to 2e66175 Compare August 12, 2026 16:56
In landscape the composer claimed nearly the whole screen, leaving no room to read the transcript. Auto-hide it as the chat scrolls and give it a reopen tab, folding it only on a screen that still carries that tab so a running agent is never stranded behind a composer that can't be recovered after process death.
@jatezzz
jatezzz force-pushed the feat/ADFA-3070-landscape-chat-scroll branch from 2e66175 to 4f97f44 Compare August 13, 2026 13:12
@jatezzz
jatezzz merged commit 8167fb0 into main Aug 13, 2026
1 check passed
@jatezzz
jatezzz deleted the feat/ADFA-3070-landscape-chat-scroll branch August 13, 2026 13:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants